<?php
define("MANTA_ROOT_DIR", dirname(dirname(__FILE__)));

/* Set up what the operating system is.
 *
 * This will be run at startup, so you can just access it as:
 *
 *   if (OS_WIN32) {
 *       do_something_for_win32();
 *   }
 */
if (substr(php_uname("s"), 0, 7) == "Windows")
	define("OS_WIN32", true);
elseif (php_uname("s") == "Linux")
	define("OS_LINUX", true);
elseif (php_uname("s") == "Darwin" || substr(php_uname("s"), 0, 3) == "Mac")
	define("OS_MACOSX", true);
elseif (php_uname("s") == "FreeBSD")
	define("OS_FREEBSD", true);
else
	define("OS_UNKNOWN", true);

if (!defined("OS_WIN32"))   define("OS_WIN32",   false);
if (!defined("OS_LINUX"))   define("OS_LINUX",   false);
if (!defined("OS_MACOSX"))  define("OS_MACOSX",  false);
if (!defined("OS_FREEBSD")) define("OS_FREEBSD", false);
if (!defined("OS_UNKNOWN")) define("OS_UNKNOWN", false);

// A useful function, currently used only for restart.
// This will also be used for running programs with no window open.
function exec_async($cmd) {
	if (OS_WIN32)
		pclose(popen("start /B ".$cmd, "r"));
	else
		exec($cmd." > /dev/null &");
	dprint("$cmd executed silently and asynchronously.");
}

function quit($exit = true) {
	global $window, $tray;
	if ($exit)
		dprint("Quitting Manta and exiting");
	else
		dprint("Quitting Manta without exiting");
	if ($window)
		$window->hide_all();
	if ($tray)
		$tray->set_visible(false);
	if (Gtk::main_level())
		Gtk::main_quit();
	if ($exit)
		exit(0);
}

// TODO: FreeBSD doesn't appear to set _, so we'll need to come up with some other way when we get to FreeBSD support.
function restart() {
	dprint("Restarting Manta");
	quit(false);
	$php_executable = null;
	dprint("Finding PHP executable");
	if (os() == OS_WIN32) {
		try {
			$obj = new COM("winmgmts:{impersonationLevel=impersonate}//./root/cimv2");
			if (is_object($obj)) {
				$processes = $obj->execquery("SELECT ExecutablePath FROM Win32_Process WHERE ProcessID = '".getmypid()."'" );
				if ($processes->count > 0) {
					// TODO: skip this silly foreach thing if we can?
					foreach ($processes as $process) {
						// See http://msdn.microsoft.com/en-us/library/aa394372(VS.85).aspx for reference
						$php_executable = $process->ExecutablePath;
					}
				}
			}
			$obj = null;
		} catch (Exception $e) { }
	} elseif (isset($_SERVER["_"])) {
		$php_executable = $_SERVER["_"];
	}
	if (!$php_executable) {
		$msg = new GtkMessageDialog(null, 0, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, "Sorry, but Manta can't work out where it's running from to resart itself. You'll have to start Manta again manually.");
		$msg->run();
		$msg->destroy();
	} else {
		dprint("Found PHP executable ($php_executable)");
		exec_async('"'.$php_executable.'" "'.p("manta.php").'"');
	}
	exit;
}


function dprint($msg) {
	echo "[".date("H:i:s")."] $msg\r\n"; // [14:15:16] Message
	// TODO: log to a file as set in config
}

// Returns a path, relative to the Manta root directory
function p($p) {
	return MANTA_ROOT_DIR."/".$p;
}

/* Provide a simple message box to the user, for information, warning, or fatal error.
 * In case of error, the user will be provided with the options of quitting and restarting.
 *
 * Do not invoke this function directly, rather through standard PHP channels, via trigger_error().
 *
 * Usage:
 *   trigger_error("This is a sample message box.", E_USER_NOTICE);
 *   trigger_error("Something may have gone wrong.", E_USER_WARNING);
 *   trigger_error("A core configuration file could not be read.", E_USER_ERROR);
 */
function __manta_error_handler($type, $msg, $file, $line) {
	switch ($type) {
	case E_ERROR:
	case E_USER_ERROR:
		$msg = "A fatal error occurred in $file, line $line, and Manta will now close.\r\n\r\n$msg";
		dprint($msg);
		if (!class_exists("Gtk"))
			die(); // Error already provided
		$mb = new GtkMessageDialog(null, 0, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_NONE, $msg);
		$mb->add_button("gtk-quit", 0);
		$mb->add_button("_Restart", 1);
		$restart = $mb->run();
		$mb->destroy();
		if ($restart)
			restart();
		else {
			quit();
		}
		break;
	case E_WARNING:
	case E_USER_WARNING:
		dprint("$file:$line: Warning: $msg");
		$mb = new GtkMessageDialog(null, 0, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, $msg);
		$mb->run();
		$mb->destroy();
		break;
	case E_NOTICE:
	case E_USER_NOTICE:
		dprint("$file:$line: Notice: $msg");
		$mb = new GtkMessageDialog(null, 0, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK, $msg);
		$mb->run();
		$mb->destroy();
		break;
	default:
		break;
	}
	return true;
}
set_error_handler("__manta_error_handler");

/* This function is pretty much the same as the error handler above,
 * running on an E_ERROR or an E_USER_ERROR, except that it's working
 * with exceptions rather than errors.
 *
 * Do not invoke this function directly, and also avoid throwing
 * exceptions which you are not intending to catch as they will cause
 * Manta to quit.
 */
function __manta_exception_handler($e) {
	try {
		$msg = "Unhandled ".get_class($e)." in ".$e->getFile().", line ".$e->getLine().".  Manta will now close.\r\n\r\n".$e->getMessage()."\r\n\r\nStack trace:\r\n".$e->getTraceAsString();
		dprint($msg);
		$mb = new GtkMessageDialog(null, 0, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_NONE, $msg);
		$mb->add_button("gtk-quit", 0);
		$mb->add_button("_Restart", 1);
		$restart = $mb->run();
		$mb->destroy();
		if ($restart)
			restart();
		else
			quit();
	} catch (Exception $e) {
		echo "Exception in exception handler: Unhandled ".get_class($e)." in ".$e->getFile().", line ".$e->getLine().".  Manta will now close.\r\n\r\n".$e->getMessage()."\r\n\r\nStack trace:\r\n".$e->getTraceAsString();
		exit(0);
	}
}
set_exception_handler("__manta_exception_handler");

function not_implemented($msg=null) {
	$m = "Sorry, but this functionality is not yet implemented.";
	if ($msg) $m .= "\r\n\r\n".$msg;
	dprint($m);
	$mb = new GtkMessageDialog(null, 0, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, $m);
	$mb->run();
	$mb->destroy();
}

// Obviously, PHP-GTK is needed to run this application.
if (!class_exists("Gtk")) trigger_error("Couldn't find PHP-GTK.  Please load the php-gtk2 extension in php.ini.\r\n", E_USER_ERROR);


abstract class MantaPage {
	private $__frame; // Used for caching the frame.

	/* TODO: this function should be being used really as it's terribly inefficient
	 * to go recreating all the page content every time it's selected, but at the
	 * moment I'm not bothering to fix this up, as it's only working first time, after
	 * that it just comes up blank (and is suddenly fast!).
	 *
	 * The best way to do this is to hide and reshow, etc. but this is not blindingly
	 * simple to do, so for the moment I'm leaving it off.
	 */
	final function create_and_fetch_frame() {
		if (!isset($this->__frame) || !$this->__frame)
			$this->__frame = $this->create_frame();
		echo $this->__frame;
		return $this->__frame;
	}
}

// Now that the basics have been set up, we can include what we need.
require_once(p("src/manta-widgets.php"));
require_once(p("src/home-page.php"));
require_once(p("src/config-page.php"));
require_once(p("src/about-page.php"));
require_once(p("src/window.php"));
require_once(p("src/trayicon.php"));
require_once(p("src/package-manager.php"));

// Now to actually start Manta.
dprint("Starting package manager");
$package_manager = new MantaPackageManager();

dprint("Creating main window");
$window = new MantaWindow();

dprint("Creating tray icon");
$tray = new MantaTrayIcon();

Gtk::main();
